package com.monkey.service;

import com.monkey.core.ErrorCode;
import com.monkey.core.WebRet;
import com.monkey.generator.dao.TMarketOrderMapper;
import com.monkey.generator.dao.TMonkeyMapper;
import com.monkey.generator.dao.TUserMonkeyMapper;
import com.monkey.generator.model.TMarketOrder;
import com.monkey.generator.model.TMarketOrderExample;
import com.monkey.generator.model.TMonkey;
import com.monkey.generator.model.TMonkeyExample;
import com.monkey.generator.model.TUserMonkey;
import com.monkey.generator.model.TUserMonkeyExample;
import com.monkey.model.comparator.*;
import com.monkey.model.monkey.Monkey;
import com.monkey.model.monkey.MonkeyTradeData;
import com.monkey.model.user.User;
import com.monkey.util.HelpUtil;
import com.monkey.util.WebConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

import static com.monkey.service.MonkeyService.*;
import static com.monkey.service.UserService.*;

/**
 * desc:
 * auth: chenxiaobin
 * data: 2018/1/4.
 */
@Service
@Transactional
public class MarketService {
    private static Logger logger = LoggerFactory.getLogger(MarketService.class);
    private static final String REDIS_PRE = "market.";
    private List<MonkeyTradeData> sellList = new ArrayList<>();

    @Resource
    private UserService userService = null;

    @Resource
    private MonkeyService monkeyService = null;

    @Resource
    private TUserMonkeyMapper userMonkeyMapper = null;
    
    @Resource
    private TMonkeyMapper monkeyMapper = null;

    @Resource
    private TMarketOrderMapper marketOrderMapper = null;

    @Resource
    private HelpUtil limitUtil = null;

    @Resource
    private WebConfig webConfig = null;

    @Resource
    private RedisTemplate<String, MonkeyTradeData> template = null;

    public void init() {
        // 还原数据
        ValueOperations<String, MonkeyTradeData> ops = template.opsForValue();
        Set<String> keys = template.keys(REDIS_PRE + "*");
        logger.info("market from redis:{}", keys);
        for (String key : keys) {
            logger.info("market load monkey:{}", key);
            MonkeyTradeData data = ops.get(key);
            User user = userService.getUser(data.getUserId());
            if (null == user) {
                logger.info("market load user error:{}", data.getUserId());
                continue;
            }
            Monkey monkey = monkeyService.getMonkey(data.getMonkeyId());
            if (null == monkey) {
                logger.info("market load monkey error:{}", data.getMonkeyId());
                continue;
            }
            monkey.setStatus(MONKEY_STATUS_MARKET);
            refreshMonkeyTradeData(data, monkey);
            sellList.add(data);
        }
        logger.info("market from redis success");
    }
    
    // 更新市场缓存中宠物数据
    private void refreshMonkeyTradeData(MonkeyTradeData data, Monkey monkey){
		data.setGeneration(monkey.getGeneration());
		data.setWeight(monkey.getWeight() / 100.0f);
		data.setGrow(monkey.getGrow() / 100.0f);
		data.setReproduct(monkey.getReproduct() / 100.0f);
		data.setBonus(monkey.getBonus() / 100.0f);
		data.setRepoductCount(monkey.getReproductCount());
		data.setUuid(monkey.getUuid());
		data.setElement(monkey.getElement());
    }

    public float getPrice(int monkeyId) {
        synchronized (this) {
            for (MonkeyTradeData d : sellList) {
                if (d.getMonkeyId() == monkeyId) {
                    return d.getPrice();
                }
            }
        }
        return 0;
    }

    public WebRet sell(User user, int monkeyId, float price) {
        int userId = user.getId();

        // 是否绑定钱包
        if (user.getWallet().isEmpty()) {
            return new WebRet(ErrorCode.WALLET_NO_BIND);
        }

        // 是否激活账号
        if (!user.getEnable()) {
            return new WebRet(ErrorCode.ACCOUNT_DISABLE);
        }

        Monkey monkey = monkeyService.getMonkey(monkeyId);
        if (userId != monkey.getUserId()) {
            return new WebRet(ErrorCode.NO_OWNER_MONKEY);
        }
        if (monkey.getStatus() != MONKEY_STATUS_NORMAL) {
            return new WebRet(ErrorCode.MONKEY_HAS_ONLY);
        }

        // 市场挂单手续费
        float water = webConfig.getFloat("market.sell.water");
        if (user.getMoney().floatValue() < water) {
            return new WebRet(ErrorCode.WALLET_LESS_ERROR);
        }

        MonkeyTradeData data = new MonkeyTradeData(monkey, userId, price);
        synchronized (this) {
            for (MonkeyTradeData d : sellList) {
                if (d.getMonkeyId() == monkeyId) {
                    return new WebRet(ErrorCode.ORDER_HAS_EXIST);
                }
            }
            sellList.add(data);
        }

        // 市场挂单手续费
        if (ErrorCode.SUCCESS != userService.updateUserMoney(user, monkeyId, -water, water, MONKEY_STATUS_NORMAL, ACTION_MARKET_SELL)) {
            return new WebRet(ErrorCode.WRITE_DB_ERROR);
        }

        // 写库
        TMarketOrder order = new TMarketOrder();
        order.setUserid(userId);
        order.setMonkeyid(monkeyId);
        order.setMoney(new BigDecimal(price));
        order.setStatus(ORDER_CREATE);
        order.setCreatetime(new Date());
        if (0 == marketOrderMapper.insert(order)) {
            logger.info("market order insert db error:{}, {}", userId, monkeyId);
        }

        // 标注状态
        monkey.setStatus(MONKEY_STATUS_MARKET);
        ValueOperations<String, MonkeyTradeData> ops = template.opsForValue();
        ops.set(REDIS_PRE + monkeyId, data);
        return new WebRet(ErrorCode.SUCCESS);
    }

    public WebRet cancel(int userId, int monkeyId) {
        Monkey monkey = monkeyService.getMonkey(monkeyId);
        if (userId != monkey.getUserId()) {
            return new WebRet(ErrorCode.NO_OWNER_MONKEY);
        }
        if (monkey.getStatus() != MONKEY_STATUS_MARKET) {
            return new WebRet(ErrorCode.MONKEY_STATUS_ERROR);
        }

        // 重置状态
        monkey.setStatus(MONKEY_STATUS_NORMAL);
        synchronized (this) {
            Iterator<MonkeyTradeData> iter = sellList.iterator();
            while (iter.hasNext()) {
                MonkeyTradeData data = iter.next();
                if (data.getMonkeyId() == monkeyId) {
                    iter.remove();
                    break;
                }
            }
        }

        // 更新记录
        TMarketOrder order = new TMarketOrder();
        order.setStatus(ORDER_CANCEL);
        TMarketOrderExample example = new TMarketOrderExample();
        example.or().andUseridEqualTo(userId).andMonkeyidEqualTo(monkeyId).andStatusEqualTo(ORDER_CREATE);
        example.setOrderByClause("createTime DESC");
        example.setLimit(1);
        if (0 == marketOrderMapper.updateByExampleSelective(order, example)) {
            logger.info("market order update cancel db error:{}, {}", userId, monkeyId);
        }

        template.delete(REDIS_PRE + monkeyId);
        return new WebRet(ErrorCode.SUCCESS);
    }

    public List<MonkeyTradeData> getList(int monkeyId, MonkeyTradeSort sort) {
        List<MonkeyTradeData> ret = new ArrayList<>();
        synchronized (this) {
            ret.addAll(sellList);
        }

        // 指定宠物
        if (0 != monkeyId) {
            List<MonkeyTradeData> tmp = new ArrayList<>();
            for (MonkeyTradeData data : ret) {
                if (data.getMonkeyId() == monkeyId) {
                    tmp.add(data);
                    return tmp;
                }
            }
            return new ArrayList<>();
        }

        int specify = sort.getSpecify();
        // 指定代数
        if (-1 != specify) {
            List<MonkeyTradeData> tmp = new ArrayList<>();
            for (MonkeyTradeData data : ret) {
                if (data.getGeneration() == specify) {
                    tmp.add(data);
                }
            }

            tmp.sort(new MonkeyTradePriceComparator(true));
            if (!limitUtil.getListWithMonkeyTradeData(tmp, sort.getOffset(), sort.getNum())) {
                return new ArrayList<>();
            }
            return tmp;
        }

        // 代数排序
        if (sort.isGeneration()) {
            ret.sort(new MonkeyTradeGenerationComparator(sort.getGeneration()));
            if (!limitUtil.getListWithMonkeyTradeData(ret, sort.getOffset(), sort.getNum())) {
                return new ArrayList<>();
            }
            return ret;
        }

        // 体重排序
        if (sort.isWeight()) {
            ret.sort(new MonkeyTradeWeightComparator(sort.getWeight()));
            if (!limitUtil.getListWithMonkeyTradeData(ret, sort.getOffset(), sort.getNum())) {
                return new ArrayList<>();
            }
            return ret;
        }

        // 生育排序
        if (sort.isReproduct()) {
            ret.sort(new MonkeyTradeReproductComparator(sort.getReproduct()));
            if (!limitUtil.getListWithMonkeyTradeData(ret, sort.getOffset(), sort.getNum())) {
                return new ArrayList<>();
            }
            return ret;
        }

        // 价格排序
        if (sort.isPrice()) {
            ret.sort(new MonkeyTradePriceComparator(sort.getPrice()));
            if (!limitUtil.getListWithMonkeyTradeData(ret, sort.getOffset(), sort.getNum())) {
                return new ArrayList<>();
            }
            return ret;
        }

        // 默认排序
        ret.sort(new MonkeyTradePriceComparator(true));
        if (!limitUtil.getListWithMonkeyTradeData(ret, sort.getOffset(), sort.getNum())) {
            return new ArrayList<>();
        }
        return ret;
    }

    public WebRet market(User user, int monkeyId, Float price) {
        int userId = user.getId();

        // 是否绑定钱包
        if (user.getWallet().isEmpty()) {
            return new WebRet(ErrorCode.WALLET_NO_BIND);
        }

        // 是否激活账号
        if (!user.getEnable()) {
            return new WebRet(ErrorCode.ACCOUNT_DISABLE);
        }

        if (price <= 0) {
            return new WebRet(ErrorCode.ORDER_LESS_ZERO);
        }

        // 判断余额是否足够
        MonkeyTradeData data = null;
        synchronized (this) {
            Iterator<MonkeyTradeData> iter = sellList.iterator();
            while (iter.hasNext()) {
                MonkeyTradeData d = iter.next();
                if (d.getMonkeyId() == monkeyId) {
                    data = d;
                    break;
                }
            }
        }
        if (null == data) {
            return new WebRet(ErrorCode.GET_DATA_ERROR);
        } else if (user.getMoney().floatValue() < data.getPrice()) {
            return new WebRet(ErrorCode.WALLET_LESS_ERROR);
        } else if (!price.equals(data.getPrice())) {
            return new WebRet(ErrorCode.ORDER_PRICE_ERROR);
        }

        Monkey monkey = monkeyService.getMonkey(monkeyId);
        if (null == monkey) {
            return new WebRet(ErrorCode.GET_DATA_ERROR);
        }
        if (monkey.getStatus() != MONKEY_STATUS_MARKET) {
            return new WebRet(ErrorCode.MONKEY_STATUS_ERROR);
        }
        if (monkey.getUserId() == userId) {
            return new WebRet(ErrorCode.YOUR_MONKEY_ERROR);
        }

        data = null;
        synchronized (this) {
            Iterator<MonkeyTradeData> iter = sellList.iterator();
            while (iter.hasNext()) {
                MonkeyTradeData d = iter.next();
                if (d.getMonkeyId() == monkeyId) {
                    monkey.setStatus(MONKEY_STATUS_NORMAL);
                    iter.remove();
                    data = d;
                    break;
                }
            }
        }
        if (null == data) {
            return new WebRet(ErrorCode.GET_DATA_ERROR);
        }

        // 扣钱
        if (ErrorCode.SUCCESS != userService.updateUserMoney(user, monkeyId, -price, 0,
                MONKEY_STATUS_NORMAL, ACTION_MARKET)) {
            return new WebRet(ErrorCode.WRITE_DB_ERROR);
        }

        // 转钱，扣手续费
        float water = webConfig.getFloat("market.pay.water");
        User user1 = userService.getUser(data.getUserId());
        if (ErrorCode.SUCCESS != userService.updateUserMoney(user1, monkeyId, price * (1 - water),
                price * water, MONKEY_STATUS_MARKET, ACTION_MARKET)) {
            return new WebRet(ErrorCode.WRITE_DB_ERROR);
        }

        // 转移宠物
        TUserMonkey userMonkey = new TUserMonkey();
        userMonkey.setUserid(userId);
        userMonkey.setAction(MONKEY_FROM_MARKET);
        TUserMonkeyExample example = new TUserMonkeyExample();
        example.or().andMonkeyidEqualTo(monkeyId);
        example.setLimit(1);
        userMonkeyMapper.updateByExampleSelective(userMonkey, example);

        monkey.setUserInfo(userId);
        user.setMonkeyNum(user.getMonkeyNum() + 1);
        user1.setMonkeyNum(user1.getMonkeyNum() - 1);

        // 更新头像
        userService.updateUserHead(user, monkey);

        // 写入记录
        TMarketOrder order = new TMarketOrder();
        order.setTouserid(userId);
        order.setStatus(ORDER_COMPLETE);
        TMarketOrderExample example1 = new TMarketOrderExample();
        example1.or().andUseridEqualTo(data.getUserId()).andMonkeyidEqualTo(monkeyId).andStatusEqualTo(ORDER_CREATE);
        example1.setOrderByClause("createTime DESC");
        example1.setLimit(1);
        if (0 == marketOrderMapper.updateByExampleSelective(order, example1)) {
            logger.info("market order update complete db error:{}, {}", userId, monkeyId);
        }

        template.delete(REDIS_PRE + monkeyId);
        logger.info("market:{}, {}, p:{}, to:{}", userId, monkeyId, price, user1.getId());
        return new WebRet(ErrorCode.SUCCESS);
    }
}
